package cn.tedu.luban.order.main.service;

import cn.tedu.luban.attach.api.AttachApi;
import cn.tedu.luban.attach.protocol.dto.AttachDTO;
import cn.tedu.luban.attach.protocol.param.AttachUpdateParam;
import cn.tedu.luban.attach.protocol.query.AttachQuery;
import cn.tedu.luban.demand.api.DemandApi;
import cn.tedu.luban.order.common.enums.OrderResultEnum;
import cn.tedu.luban.order.common.enums.OrderStatusEnum;
import cn.tedu.luban.order.main.converter.OrderLogConverter;
import cn.tedu.luban.order.main.repository.OrderLogRepository;
import cn.tedu.luban.order.main.repository.OrderRepository;
import cn.tedu.luban.order.protocol.bo.AttachInfoBO;
import cn.tedu.luban.order.protocol.bo.OrderBO;
import cn.tedu.luban.order.protocol.bo.OrderLogBO;
import cn.tedu.luban.order.protocol.dto.OrderMessageDTO;
import cn.tedu.luban.order.protocol.param.OrderConfirmParam;
import cn.tedu.luban.order.protocol.param.OrderCreateParam;
import cn.tedu.luban.order.protocol.param.OrderFinishParam;
import cn.tedu.luban.order.protocol.param.OrderLogParam;
import cn.tedu.luban.order.protocol.param.OrderParam;
import cn.tedu.luban.order.protocol.param.OrderSignParam;
import cn.tedu.luban.order.protocol.query.FrontOrderListQuery;
import cn.tedu.luban.passport.protocol.jwt.UserPrinciple;
import cn.tedu.luban.passport.sdk.security.LubanSecurityContext;
import com.sun.org.apache.bcel.internal.generic.IF_ACMPEQ;
import com.tedu.inn.protocol.ListRecordTotalBO;
import com.tedu.inn.protocol.exception.BusinessException;
import java.util.ArrayList;
import java.util.List;
import java.util.UUID;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

@Service
public class OrderFrontService {
    @Autowired
    private OrderRepository orderRepository;
    @Autowired
    private OrderLogRepository orderLogRepository;
    @Autowired
    private DemandApi demandApi;
    @Autowired
    private OrderLogConverter orderLogConverter;
    @Autowired
    private MessageService messageService;
    public String orderCreate(OrderCreateParam param) throws BusinessException {
        Boolean grabOk=false;
        //1.抢单先
        grabOk= demandApi.grabOrder(param.getRequestOrderNo());
        //2.判断抢单结果
        if (!grabOk){
            throw new BusinessException(OrderResultEnum.ORDER_GRAB_FAIL);
        }else{
            //3.抢单成功,下单
            //生成uuid
            String orderNo= UUID.randomUUID().toString();
            Long userId=getUserId();
            Integer status= OrderStatusEnum.ORDER_CREATE_SUCCESS.getStatus();
            param.setOrderNo(orderNo);
            param.setUserId(userId);
            param.setStatus(status);
            //4 新增
            orderRepository.saveOrder(param);
            //5 记录日志
            OrderLogParam orderLogParam = orderLogConverter.assembleOrderLogParam(userId,orderNo, OrderStatusEnum.ORDER_CREATE_SUCCESS);
            orderLogRepository.saveOrderLog(orderLogParam);
            //6. 发送延迟消息
            messageService.sendDelayMessage(orderNo);
            return orderNo;
        }
    }

    private Long getUserId() throws BusinessException {
        UserPrinciple userPrinciple = LubanSecurityContext.getLoginToken();
        if (userPrinciple == null) {
            throw new BusinessException(OrderResultEnum.USER_TOKEN_VERIFY_FAILED);
        }
        return userPrinciple.getId();
    }

    public void orderDelay(String orderNo) throws BusinessException {
        //1. 查询是否存在
        OrderBO orderBO=orderRepository.getOrderByOrderNo(orderNo);
        //2. 判断状态
        if (orderBO==null||orderBO.getId()==null){
            throw new BusinessException(OrderResultEnum.ORDER_EMPTY);
        }
        Integer status=orderBO.getStatus();
        if (status==10){
            //关闭订单，归还订单
            OrderParam orderParam = new OrderParam();
            orderParam.setOrderNo(orderNo);
            orderParam.setStatus(OrderStatusEnum.CANCELLED_BY_EXPIRE.getStatus());
            orderRepository.closeOrder(orderParam);
            //记录关闭日志 系统关闭
            OrderLogParam orderLogParam = orderLogConverter.assembleOrderLogParam(999L, orderNo, OrderStatusEnum.CANCELLED_BY_EXPIRE);
            orderLogRepository.saveOrderLog(orderLogParam);
            //归还需求单
            demandApi.returnOrder(orderBO.getRequestOrderNo());
        }
    }

    public ListRecordTotalBO<OrderBO> orderList(FrontOrderListQuery query) throws BusinessException {
        ListRecordTotalBO listRecordTotalBO=null;
        //给query封装一个userId select * from order where user_id=#{userId}
        //and status in (10,20,50)
        query.setUserId(getUserId());
        //1. 查询total
        Long total=orderRepository.countOrders(query);
        if (total==0){
            listRecordTotalBO=new ListRecordTotalBO(null,0L);
        }else{
            //2. 查询并且封装分页数据
            List<OrderBO> orderBOS = orderRepository.queryOrders(query);
            listRecordTotalBO=new ListRecordTotalBO(orderBOS,total);
        }
        return listRecordTotalBO;
    }

    public OrderBO orderDetail(String orderNo) throws BusinessException {
        //1. 利用orderNo查询order数据
        OrderBO orderBO = orderRepository.getOrderByOrderNo(orderNo);
        //2.判断是否空
        if (orderBO==null|| orderBO.getId()==null){
            throw new BusinessException(OrderResultEnum.ORDER_EMPTY);
        }
        Integer status = orderBO.getStatus();//10 20 50 30
        if (status==10){
            return orderBO;
        }else if (status==20) {
            //3. 封装签到时间和完成时间 signTime属性 finishTime
            putSignTime(orderBO);
        }else if(status==50 || status== 30){
            //施工中 和完成待结算
            //3. 封装签到时间和完成时间 signTime属性 finishTime
            putSignTime(orderBO);
            //4. 远程调用封装图片数据 attachList
            putAttaches(orderBO);
        }
        return orderBO;
    }
    @Autowired
    private AttachApi attachApi;
    private void putAttaches(OrderBO orderBO) {
        //将该订单绑定的图片都查询 并且封装给BO
        Integer bizType=200;
        Integer bizId=orderBO.getId().intValue();
        AttachQuery attachQuery=new AttachQuery();
        attachQuery.setBusinessId(bizId);
        attachQuery.setBusinessType(bizType);
        List<AttachDTO> attachDTOS = attachApi.getAttachInfoByParam(attachQuery);
        List<AttachInfoBO> attachInfoBOS=new ArrayList<>();
        for (AttachDTO attachDTO : attachDTOS) {
            //attachDTO拿到图片所有数据详情,包括图片名称 拼接url放到infoBO里
            AttachInfoBO attachInfoBO=new AttachInfoBO();
            String url="http://localhost:8092/static/"+attachDTO.getFileUuid();
            attachInfoBO.setUrl(url);
            attachInfoBOS.add(attachInfoBO);
        }
        //结束图片封装最终交给orderBO使用
        orderBO.setAttachInfoBO(attachInfoBOS);
    }

    private void putSignTime(OrderBO orderBO) {
        //订单操作 抢到 施工完成 order_log有记录 绑定的是订单编号
        String orderNo=orderBO.getOrderNo();
        List<OrderLogBO> orderLogBOS =
            orderLogRepository.getOrderLogByOrderNo(orderNo);
        for (OrderLogBO orderLogBO : orderLogBOS) {
            String operateName = orderLogBO.getOperateName();
            if (operateName!=null && operateName.equals("签到")){
                //当前日志的操作时间就是signTime
                orderBO.setSignTime(orderLogBO.getOperateTime());
            }
        }
    }

    public void orderSign(OrderSignParam param) throws BusinessException {
        String orderNo = param.getOrderNo();
        OrderBO orderBO = orderRepository.getOrderByOrderNo(orderNo);
        if (orderBO==null||orderBO.getId()==null){
            throw new BusinessException(OrderResultEnum.ORDER_EMPTY);
        }
        //定位
        checkLocations();
        //流转状态
        checkStatusTransfer(orderBO.getStatus(),OrderStatusEnum.ORDER_SIGN_SUCCESS);
        //更新状态
        OrderParam orderParam=new OrderParam();
        orderParam.setOrderNo(orderNo);
        orderParam.setStatus(20);
        orderRepository.updateStatus(orderParam);
        OrderLogParam orderLogParam = orderLogConverter.assembleOrderLogParam(getUserId(), orderNo, OrderStatusEnum.ORDER_SIGN_SUCCESS);
        orderLogRepository.saveOrderLog(orderLogParam);
    }

    private void checkStatusTransfer(Integer oldStatus, OrderStatusEnum orderStatusEnum) throws BusinessException {
        Integer newStatus=orderStatusEnum.getStatus();
        if (oldStatus==10&&newStatus!=20){
            throw new BusinessException(OrderResultEnum.ORDER_STATUS_TRANSFORM_ERROR);
        }
        if (oldStatus==20&&newStatus!=50){
            throw new BusinessException(OrderResultEnum.ORDER_STATUS_TRANSFORM_ERROR);
        }
        //50状态是在施工图片确认绑定时 第一次施工绑定 20-50 施工图片可以上传多次 50 - 50
        //50施工结束 完成待结算
        if (oldStatus==50&&newStatus!=30&&newStatus!=50){
            throw new BusinessException(OrderResultEnum.ORDER_STATUS_TRANSFORM_ERROR);
        }
        if (oldStatus==30&&newStatus!=40){
            throw new BusinessException(OrderResultEnum.ORDER_STATUS_TRANSFORM_ERROR);
        }
    }
    private void checkLocations() {
        //TODO
    }
    public void orderConfirm(OrderConfirmParam param) throws BusinessException {
        String orderNo = param.getOrderNo();
        OrderBO orderBO = orderRepository.getOrderByOrderNo(orderNo);
        if (orderBO==null||orderBO.getId()==null){
            throw new BusinessException(OrderResultEnum.ORDER_EMPTY);
        }
        checkStatusTransfer(orderBO.getStatus(),OrderStatusEnum.ORDER_ATTACH_CONFIRM);
        if (orderBO.getStatus()!=50){
            //说明当前订单状态是20 需要将其更新为50 第一次上传施工图片
            OrderParam orderParam=new OrderParam();
            orderParam.setOrderNo(orderNo);
            orderParam.setStatus(50);
            orderRepository.updateStatus(orderParam);//
        }
        OrderLogParam orderLogParam = orderLogConverter.assembleOrderLogParam(getUserId(), orderNo, OrderStatusEnum.ORDER_ATTACH_CONFIRM);
        orderLogRepository.saveOrderLog(orderLogParam);
        //绑定图片
        List<AttachUpdateParam> attachUpdateParams=new ArrayList<>();
        //循环本次图片上传的图片id们
        for (Long attachId : param.getAttachIds()) {
            AttachUpdateParam attachUpdateParam=new AttachUpdateParam();
            //图片是否是封面
            attachUpdateParam.setIsCover(1);
            //图片id
            attachUpdateParam.setId(attachId.intValue());
            //绑定bizId 是当前订单id
            attachUpdateParam.setBusinessId(orderBO.getId().intValue());
            //绑定的bizType 200
            attachUpdateParam.setBusinessType(200);
            attachUpdateParams.add(attachUpdateParam);
        }
        attachApi.batchUpdateAttachByIdList(attachUpdateParams);
    }

    public void orderFinish(OrderFinishParam param) throws BusinessException {
        String orderNo=param.getOrderNo();
        OrderBO orderBO = orderRepository.getOrderByOrderNo(orderNo);
        if (orderBO==null||orderBO.getId()==null){
            throw new BusinessException(OrderResultEnum.ORDER_EMPTY);
        }
        //2. 检查订单流转状态 当前订单状态 和目标状态
        checkStatusTransfer(orderBO.getStatus(),OrderStatusEnum.ORDER_SERVICE_SUCCESS_UN_SETTLE);
        //3. 订单状态修改 update order set status=30 where order_no=#{orderNo}
        OrderParam orderParam=new OrderParam();
        orderParam.setOrderNo(orderNo);
        orderParam.setStatus(30);
        orderRepository.updateStatus(orderParam);
        //4. 记录操作日志
        OrderLogParam orderLogParam = orderLogConverter.assembleOrderLogParam(getUserId(), orderNo, OrderStatusEnum.ORDER_SERVICE_SUCCESS_UN_SETTLE);
        orderLogRepository.saveOrderLog(orderLogParam);
        //5. 发送消息,让后续流程步骤在消费者里慢慢完成
        //MQDTO 除了实现了一个序列化,其他属性和orderBO完全一样
        OrderMessageDTO orderMqDTO=new OrderMessageDTO();
        BeanUtils.copyProperties(orderBO,orderMqDTO);
        //没有实现生产者
        messageService.sendFinishMessage(orderMqDTO);
    }

    public void orderComplete(String orderNo) throws BusinessException {
        OrderBO orderBO = orderRepository.getOrderByOrderNo(orderNo);
        if (orderBO==null||orderBO.getId()==null){
            throw new BusinessException(OrderResultEnum.ORDER_EMPTY);
        }
        checkStatusTransfer(orderBO.getStatus(),OrderStatusEnum.ORDER_FINISH);
        OrderParam orderParam=new OrderParam();
        orderParam.setOrderNo(orderNo);
        orderParam.setStatus(40);
        orderRepository.updateStatus(orderParam);
        OrderLogParam orderLogParam = orderLogConverter.assembleOrderLogParam(999L, orderNo, OrderStatusEnum.ORDER_FINISH);
        orderLogRepository.saveOrderLog(orderLogParam);
    }
}
